#include "muduo/protoc/codec.h"
#include "muduo/protoc/dispatcher.h"
#include "muduo/net/TcpServer.h"
#include "muduo/net/EventLoop.h"

#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"

#include <stdio.h>
#include <unistd.h>
#include <unordered_map>
#include <memory>

#include "request.pb.h"
class Server{
    typedef std::shared_ptr<google::protobuf::Message> MessagePtr;
    typedef std::shared_ptr<bit::AddRequest> AddRequestPtr;
    typedef std::shared_ptr<bit::AddResponse> AddResponsePtr;
    typedef std::shared_ptr<bit::TranslateRequest> TranslateRequestPtr;
    typedef std::shared_ptr<bit::TranslateResponse> TranslateResponsePtr;
public:
    Server(int port)
    :_server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port), "server", muduo::net::TcpServer::kReusePort)
    ,_dispatcher(std::bind(&Server::onUnknownMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))
    ,_codec(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))
    {
        _dispatcher.registerMessageCallback<bit::AddRequest>(std::bind(&Server::onAdd, this, std::placeholders::_1,
                                                             std::placeholders::_2, std::placeholders::_3));
        _dispatcher.registerMessageCallback<bit::TranslateRequest>(std::bind(&Server::onTranslate, this, std::placeholders::_1,
                                                             std::placeholders::_2, std::placeholders::_3));
        _server.setMessageCallback(std::bind(&ProtobufCodec::onMessage, &_codec, std::placeholders::_1, std::placeholders::_2,
                                     std::placeholders::_3));
        _server.setConnectionCallback(std::bind(&Server::onConnetion, this, std::placeholders::_1));
        
    }
    void start(){
        _server.start();
        _baseloop.loop();
    }
private:
    void onConnetion(const muduo::net::TcpConnectionPtr & conn){
        if(conn->connected()){
            LOG_INFO << "连接成功\n";
        }else{
            LOG_INFO << "连接失败\n";
        }
    }
    void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp){
            LOG_INFO << "onUnkownMessage: " << message->GetTypeName();
            conn->shutdown();
    }
    void onAdd(const muduo::net::TcpConnectionPtr& conn, const AddRequestPtr& message, muduo::Timestamp){
        // 1、提取message中的有效信息，也就是需要翻译的内容
        int num1= message->num1();
        int num2= message->num2();
        // 2、进行翻译
        int result = num1 + num2;
        std::cout << "add : " << result << std::endl;
        // 3、组织protobuf相应
        bit::AddResponse res;
        res.set_result(result);
        // 4、发送响应
        _codec.send(conn, res);
    }
    std::string translate(const std::string& str){
        std::unordered_map<std::string,std::string> mp = {
            {"apple", "苹果"},
            {"banana", "香蕉"},
            {"car", "汽车"}
        };
        if(mp.count(str)) return mp[str];
        else return "unknown";
    }
    void onTranslate(const muduo::net::TcpConnectionPtr& conn, const TranslateRequestPtr& message, muduo::Timestamp){
        // 1、提取message中的有效信息，也就是需要翻译的内容
        std::string req_msg = message->msg();
        // 2、进行翻译
        std::string resp_msg = translate(req_msg);
        std::cout << "translate : " << resp_msg << std::endl;
        // 3、组织protobuf相应
        bit::TranslateResponse res;
        res.set_msg(resp_msg);
        // 4、发送响应
        _codec.send(conn, res);
    }
private:
    muduo::net::EventLoop _baseloop;
    muduo::net::TcpServer _server;
    ProtobufDispatcher _dispatcher;
    ProtobufCodec _codec;
};
int main()
{
    Server svr(8080);
    svr.start();
    return 0;
}